import { Logger } from '../logger';

const profileData: Record<string, { callTimes: number, execTime: number }> = {};

/**
 * 分析对象方法的执行效率，统计总时间以及执行次数
 * @param target 目标对象
 * @param propertyKey 目标方法名
 * @param descriptor 
 * @param limitTime RESERVED
 * @decorator profile
 */
export const profile = function (target: object, propertyKey: string, descriptor: PropertyDescriptor, limitTime: number | undefined = undefined) {
    const originalMethod = descriptor.value;
    descriptor.value = function (...args: any[]) {
        // 初始化数据
        const key = `${target.constructor.name}.${propertyKey}`;
        if (!profileData[key]) {
            profileData[key] = { callTimes: 0, execTime: 0 };
        }
        // 记录调用次数
        profileData[key].callTimes++;
        // 统计执行时间
        const timeBegin = Game.cpu.getUsed();
        const result = originalMethod.apply(this, args);    // 调用原始方法
        const timeEnd = Game.cpu.getUsed();
        // 记录执行时间
        const executionTime = timeEnd - timeBegin;
        if (limitTime && executionTime > limitTime) {
            // 如果执行时间超过限制，则记录一下
            Logger.warn(`${key} 执行时间超过 ${limitTime}ms (限制 ${limitTime}ms)`, 'PROFILE');
        }
        profileData[key].execTime += executionTime;
        // 返回结果
        return result;
    };
    return descriptor;
};

/**
 * @param methodKey 方法名，形如 `ClassName.methodName`
 * @returns 一个对象，包含总执行次数、总执行时间、平均执行时间、CPU 占用比
 */
export const getProfileDataOf = function (methodKey: string) {
    if (!profileData[methodKey]) {
        return null;
    }
    else {
        const callTimes = profileData[methodKey].callTimes;
        const execTime = profileData[methodKey].execTime;
        const limit = Game.cpu.limit === 0 ? 100000 : Game.cpu.limit;
        return {
            totalCallTimes: callTimes,
            totalExecuteTime: execTime,
            averageExecuteTime: execTime / callTimes,
            percentage: execTime / callTimes / limit * 100
        };
    }
};

/**
 * 获取最耗 CPU 的 10 个方法
 */
export const getTop10CostyMethods = function () {
    const methods = Object.keys(profileData);
    methods.sort((a, b) => {
        const aData = profileData[a];
        const bData = profileData[b];
        return bData.execTime - aData.execTime;
    }).slice(0, 10);
    return methods;
};

/**
 * 在执行超时时，输出警告
 * @param limit 可以设置限制的 CPU 时间
 */
export const timeLimit = function (limit: number) {
    return function (target: object, propertyKey: string, descriptor: PropertyDescriptor) {
        return profile(target, propertyKey, descriptor, limit);
    };
};